package com.example.bootdemo.configuration;

import com.example.bootdemo.service.impl.UserDetailServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailServiceImpl userDetailService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder());



        /**
        auth     //使用内存存储
                .inMemoryAuthentication()
                //使用BCrypt密码编码器
                .passwordEncoder(passwordEncoder())
                //配置user用户、密码和角色，此处配置的user用户密码会覆盖系统随机生成的uuID密码
                // 密文使用springboot-cli指令 spring encodepassword user得到
                .withUser("user").password("$2a$10$bVicNl2vVT0H70APYQYmde9bauRRaENu0HN7HpzByJCtLy0FU0ubu")
                .roles("USER")
                .and()
                //配置admin用户、密码和角色
                .withUser("admin")
                .password("$2a$10$DHtuK1bibHqbAwoGgLi4zOiNjULuHQ2qhIs/ziCw/9T2fqF320cJu")
                .roles("ADMIN","USER");
         */
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests().antMatchers("/index/user").hasAnyRole("Admin","Developer","SystemAdmin")
                .antMatchers("/index/admin").hasAnyRole("Admin","SystemAdmin")
                .anyRequest().authenticated()
                .antMatchers("/security/user/write").hasAnyRole("Admin","SystemAdmin")
                .anyRequest().authenticated()
                .antMatchers("/security/user/read").hasAnyRole("Admin","Developer","SystemAdmin","Guest")
                .anyRequest().authenticated()
                .antMatchers("/security/role/write").hasRole("SystemAdmin")
                .antMatchers("security/user/role/write").hasAnyRole("Admin","SystemAdmin")
                .anyRequest().authenticated()
                .antMatchers("/login").permitAll()
                .and().formLogin().loginProcessingUrl("/login").
                usernameParameter("username").passwordParameter("password")
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth) throws IOException, ServletException {
                        Object principal = auth.getPrincipal();
                        response.setContentType("application/json;charset=utf-8");
                        response.setStatus(200);
                        PrintWriter writer = response.getWriter();
                        Map<String,Object> map = new HashMap<>();
                        map.put("status",200);
                        map.put("msg","login success");
                        map.put("data",principal);
                        ObjectMapper objectMapper = new ObjectMapper();
                        writer.write(objectMapper.writeValueAsString(map));
                        writer.flush();
                        writer.close();
                    }
                }).failureHandler(new AuthenticationFailureHandler() {
            @Override
            public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException ex) throws IOException, ServletException {
                response.setContentType("application/json ;charset=utf-8");
                PrintWriter writer = response.getWriter();
                response.setStatus(401);
                Map<String,Object> map = new HashMap<>();
                map.put("status",401);
                if(ex instanceof LockedException){
                    map.put("msg","账号被锁定，登录失败");
                }else if(ex instanceof BadCredentialsException){
                    map.put("msg","账号或密码输入错误，登录失败");
                }else if(ex instanceof DisabledException){
                    map.put("msg","账户被禁用，登录失败");
                }else if(ex instanceof CredentialsExpiredException){
                    map.put("msg","密码过期，登录失败");
                }else{
                    map.put("msg","登录失败");
                }
                ObjectMapper objectMapper = new ObjectMapper();
                writer.write(objectMapper.writeValueAsString(map));
                writer.flush();
                writer.close();
            }
        })
                .permitAll()
                 .and();
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return  new BCryptPasswordEncoder();
    }

}
